
def is_model(inst):
    return getattr(inst, '__model__', False)
    
class Property(object):
    ''' Properties are like fields in a db for ``riakmodel.api.Model``
    
        Keyword Arguments:
            type: required - The type the field should conform to. Can be str, int, datetime, etc.
                                                               
            required(``bool``): optional - Property must have a value specified.
            
            repeated(``bool``): optional - Property value is a list containing values of ``type``.
            
            info(``str``): optional - A place to store a comment or note about the field.
            
    '''
    autonowadd = False
    autonow = False
    
    has_default = False
    
    def __init__(self, **kwargs):
        
        if 'type' not in kwargs:
            raise ValueError("property must have type")
            
        if 'indexed' in kwargs and not isinstance(kwargs.get('indexed'), bool):
            raise ValueError('indexed must be bool')
         
        if 'repeated' in kwargs and not isinstance(kwargs.get('repeated'), bool):
            raise ValueError('repeated must be bool')
        
        if 'required' in kwargs and not isinstance(kwargs.get('required'), bool):
            raise ValueError('required must be bool')
            
        self.type = kwargs.pop('type', None)
        self.required = kwargs.pop('required', False)
        self.info = kwargs.pop('info', None)
        self.repeated = kwargs.pop('repeated', False)
        self.indexed = kwargs.pop('indexed', False)
        
        # TODO: choices
        self.choices = kwargs.pop('choices', None)
        
        if 'default' in kwargs:
            self.has_default = True
        
        default = kwargs.pop('default', None)
        
        # ensure lists default to something iterable
        if isinstance(type, list) and default is None:
            self.default = []
        else:
            self.default = default
        
    def get_default(self):
        return self.default
        
    def _set_id(self, id):
        self.id = id
        
    def _set_model(self, model):
        self.model = model
        
    def get_id(self):
        ''' Returns the fields id.
        '''
        return str(self.id)
     
    def get_indexed(self):
        return self.indexed
        
    def get_type(self):
        ''' Returns the type the field should be.
        '''
        return self.type
        
    def get_required(self):
        ''' Returns true if the field is required. 
        '''
        return self.required
                
    def get_info(self):
        ''' Returns the help/info string. 
        '''
        return self.info
    
    def get_repeated(self):
        ''' 
            Returns:
                True if this field has repeating values.
        '''
        return self.repeated
     
    def encode(self, v):
        ''' Encodes values to be store stored in the db.
        '''
        if self.get_repeated():
            return self.encode_repeated(v)
        else:
            return self.encode_single(v)
        
    def encode_single(self, value):
        ''' Encodes value for the db.
        '''
        raise NotImplementedError
        
    def encode_repeated(self, values):
        ''' Encodes values to be stored in the db. Called if this field repeats. 
        '''
        raise NotImplementedError
        
    def decode(self, v):
        ''' Decodes values from the db into the properties type. 
        '''
        if self.get_repeated():
            return self.decode_repeated(v)
        else:
            return self.decode_single(v)
        return v
    
    def decode_single(self, v):
        raise NotImplementedError
     
    def decode_repeated(self, v):
        raise NotImplementedError
        
    def encode_index_values(self, v):
        ''' Returns a list of values to pass to secondary indexes.
        
            Returns:
                A list of values to pass to riak secondary indexes,
                corresponding with self.get_index_types() and
                self.get_index_keys()
        '''
        raise NotImplementedError
        
    def get_index_types(self):
        ''' Returns a list of index types.
        
            Returns:
                A list of ``'bin'`` or ``'int'`` depending on the riak secondary index
                types.
        '''
        raise NotImplementedError
        
    def get_index_keys(self):
        ''' Returns the keys of secondary indexes.
        
            Returns:
                A list of secondary index key names corresponding with types
                returned from get_index_types.
        '''
        raise NotImplementedError
     
    def encode_other(self, other):
        return other
        
    def __gt__(self, other):
        return (self.get_index_keys()[0], '>', self.encode_other(other))
        
    
    def __lt__(self, other):
        return (self.get_index_keys()[0], '<', self.encode_other(other))
        
    
    def __eq__(self, other):
        return (self.get_index_keys()[0], '==', self.encode_other(other))
        
    def __repr__(self):
        return "Property(%s, type=%s, required=%s)" % (
            self.get_id(),
            self.get_type(),
            self.get_required()
        )
